#!/usr/bin/python3
# -*- coding: utf-8 -*-

from abc import ABC, abstractmethod
from .user_service import UserService
from .token_service import TokenService

class AuthStrategy(ABC):
    """认证策略抽象基类"""
    
    @abstractmethod
    def authenticate(self, credentials):
        """验证用户身份
        
        Args:
            credentials: 凭据信息
            
        Returns:
            tuple: (is_valid, user, message)
        """
        pass

class UsernamePasswordStrategy(AuthStrategy):
    """用户名密码认证策略"""
    
    def authenticate(self, credentials):
        """使用用户名密码验证
        
        Args:
            credentials: 包含username和password的字典
            
        Returns:
            tuple: (is_valid, user, message)
        """
        username = credentials.get('username')
        password = credentials.get('password')
        
        if not username:
            return False, None, "缺少用户名"
        
        if not password:
            return False, None, "缺少密码"
        
        user = UserService.authenticate(username, password)
        
        if user:
            return True, user, "认证成功"
        else:
            return False, None, "用户名或密码错误"

class TokenStrategy(AuthStrategy):
    """Token认证策略"""
    
    def authenticate(self, credentials):
        """使用token验证
        
        Args:
            credentials: 包含token的字典
            
        Returns:
            tuple: (is_valid, user, message)
        """
        token = credentials.get('token')
        
        if not token:
            return False, None, "缺少token"
        
        is_valid, result = TokenService.validate_token(token)
        
        if is_valid:
            return True, result, "认证成功"
        else:
            return False, None, result.get('message', "无效的token")

class AuthService:
    """认证服务"""
    
    # 认证策略映射
    _strategies = {
        'password': UsernamePasswordStrategy(),
        'token': TokenStrategy()
    }
    
    @classmethod
    def authenticate(cls, auth_type, credentials):
        """根据认证类型执行认证
        
        Args:
            auth_type: 认证类型，支持'password'或'token'
            credentials: 凭据信息
            
        Returns:
            tuple: (is_valid, user, message)
        """
        if auth_type not in cls._strategies:
            return False, None, f"不支持的认证类型: {auth_type}"
        
        strategy = cls._strategies[auth_type]
        return strategy.authenticate(credentials)
    
    @classmethod
    def register_user(cls, user_data):
        """注册新用户
        
        Args:
            user_data: 用户数据字典，包含username、password等信息
            
        Returns:
            dict: 创建的用户信息字典
            
        Raises:
            ValueError: 用户名已存在或其他创建失败的情况
        """
        return UserService.create_user(user_data)
    
    @classmethod
    def login(cls, username, password):
        """用户登录
        
        Args:
            username: 用户名
            password: 密码
            
        Returns:
            tuple: (token, user) token是字符串，user是用户信息字典
        """
        is_valid, user, message = cls.authenticate('password', {
            'username': username,
            'password': password
        })
        
        if not is_valid:
            raise ValueError(message)
        
        # 生成token
        user_dict = user.to_dict(exclude_keys=['password'])
        token, _ = TokenService.create_token(user_dict)
        
        # 将token保存到数据库
        try:
            import sqlite3
            from flask import current_app
            
            conn = sqlite3.connect(current_app.config['DB_PATH'])
            cursor = conn.cursor()
            cursor.execute('UPDATE users SET token = ? WHERE username = ?', (token, username))
            conn.commit()
            conn.close()
            print(f"Token已保存到用户 {username} 的数据库记录")
        except Exception as e:
            print(f"保存token到数据库时出错: {str(e)}")
        
        # 返回token和用户信息
        return token, user_dict
    
    @classmethod
    def validate_user_token(cls, token):
        """验证用户token
        
        Args:
            token: 用户token
            
        Returns:
            tuple: (is_valid, user_info, message)
        """
        return cls.authenticate('token', {'token': token}) 